package cn.huiyunche.base.service.interfaces.impl;

import cn.huiyunche.base.service.constant.QiniuConstant;
import cn.huiyunche.base.service.enums.*;
import cn.huiyunche.base.service.form.AttachForm;
import cn.huiyunche.base.service.framework.utils.HYCUtils;
import cn.huiyunche.base.service.framework.utils.QiniuUtils;
import cn.huiyunche.base.service.interfaces.*;
import cn.huiyunche.base.service.mappers.*;
import cn.huiyunche.base.service.mappers.ext.CWaybillViewMapper;
import cn.huiyunche.base.service.mappers.ext.SWaybillViewMapper;
import cn.huiyunche.base.service.model.*;
import cn.huiyunche.base.service.utils.DateUtils;
import cn.huiyunche.base.service.utils.JavaSmsApi;
import cn.huiyunche.base.service.vo.*;
import cn.huiyunche.tools.basic.exceptions.BusinessException;
import com.alibaba.fastjson.JSONArray;
import io.jsonwebtoken.lang.Collections;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CWaybillVeneerServiceImpl implements CWaybillVeneerService {

    private static final Logger LOGGER = LoggerFactory.getLogger(CWaybillVeneerServiceImpl.class);

    private static String REDIS_LOCK_WAYBILL_GRAB_PRE = "lock:waybill:grab:";

    @Autowired
    private CWaybillViewMapper cWaybillViewMapper = null;

    @Autowired
    private UserService userService = null;

    @Autowired
    private BCompanyUserService bCompanyUserService = null;

    @Autowired
    private DriverCertInfoService driverCertInfoService = null;

    @Autowired
    private RedisCacheManager redisCacheManager;

    @Autowired
    private CWaybillMapper cwaybillMapper = null;

    @Autowired
    private CWaybillContactsService cWaybillContactsService = null;

    @Autowired
    private TruckInfoService truckInfoService = null;

    @Autowired
    private CWaybillDetailMapper cWaybillDetailMapper = null;

    @Autowired
    private SServiceOrderMapper sServiceOrderMapper = null;

    @Autowired
    private WaybillBidService waybillBidService = null;

    @Autowired
    private SOrderService sOrderService = null;

    @Autowired
    private SServiceOrderService sServiceOrderService = null;

    @Autowired
    private SendMessageService sendMessageService = null;

    @Autowired
    private CWaybillAttachMapper cWaybillAttachMapper = null;

    @Autowired
    private CWaybillStatusLogService cWaybillStatusLogService = null;

    @Autowired
    private SServiceOrderStatusLogService sServiceOrderStatusLogService = null;

    @Autowired
    private SServiceOrderTrailMapper sServiceOrderTrailMapper = null;

    @Autowired
    private SWaybillViewMapper sWaybillViewMapper = null;

    @Autowired
    private SServiceOrderVehicleService sServiceOrderVehicleService = null;

    @Autowired
    private BVehicleBrandService bVehicleBrandService = null;

    @Autowired
    private BVehicleService bVehicleService = null;

    @Autowired
    private SUserDevicesMapper sUserDevicesMapper = null;

    @Autowired
    private JPushService jPushService = null;

    @Autowired
    private CWaybillService cWaybillService = null;

    private CWaybillService getCWaybillService() {
        return this.cWaybillService;
    }

    private JPushService getJPushService() {
        return this.jPushService;
    }

    private SUserDevicesMapper getSUserDevicesMapper() {
        return this.sUserDevicesMapper;
    }

    private BVehicleService getBVehicleService() {
        return this.bVehicleService;
    }

    private BVehicleBrandService getBVehicleBrandService() {
        return this.bVehicleBrandService;
    }

    private SServiceOrderVehicleService getSServiceOrderVehicleService() {
        return this.sServiceOrderVehicleService;
    }

    private SWaybillViewMapper getSWaybillViewMapper() {
        return this.sWaybillViewMapper;
    }

    private SServiceOrderTrailMapper getSServiceOrderTrailMapper() {
        return this.sServiceOrderTrailMapper;
    }

    private SServiceOrderStatusLogService getSServiceOrderStatusLogService() {
        return this.sServiceOrderStatusLogService;
    }

    private CWaybillStatusLogService getCWaybillStatusLogService() {
        return this.cWaybillStatusLogService;
    }

    private CWaybillAttachMapper getCWaybillAttachMapper() {
        return this.cWaybillAttachMapper;
    }

    private SendMessageService getSendMessageService() {
        return this.sendMessageService;
    }

    private SServiceOrderService getSServiceOrderService() {
        return this.sServiceOrderService;
    }

    private SOrderService getSOrderService() {
        return this.sOrderService;
    }

    private WaybillBidService getWaybillBidService() {
        return this.waybillBidService;
    }

    private SServiceOrderMapper getSServiceOrderMapper() {
        return this.sServiceOrderMapper;
    }

    private CWaybillDetailMapper getCWaybillDetailMapper() {
        return this.cWaybillDetailMapper;
    }

    private TruckInfoService getTruckInfoService() {
        return this.truckInfoService;
    }

    private CWaybillContactsService getCWaybillContactsService() {
        return this.cWaybillContactsService;
    }

    private CWaybillMapper getCWaybillMapper() {
        return this.cwaybillMapper;
    }

    private DriverCertInfoService getDriverCertInfoService() {
        return this.driverCertInfoService;
    }

    private BCompanyUserService getBCompanyUserService() {
        return this.bCompanyUserService;
    }

    private UserService getUserService() {
        return this.userService;
    }

    private CWaybillViewMapper getCWaybillViewMapper() {
        return this.cWaybillViewMapper;
    }

    private List<Long> getUserIdList() {
        LOGGER.info("select stan cwaybill list params currentUser");
        try {
            UserVo currentUserVo = this.getUserService().getCurrentUserVo();
            LOGGER.info("select stan cwaybill list params currentUser : {}.", currentUserVo);
            if (null == currentUserVo) {
                return null;
            }
            Long userId = currentUserVo.getId();
            Integer userType = currentUserVo.getType();
            List<Long> userIdList = new ArrayList<>();
            if (userType == UserTypeEnum.COMPANY.getValue()) {
                Long companyId = this.getBCompanyUserService().getCompanyIdByUserId(userId);
                List<BCompanyUser> BCompanyUserList = this.getBCompanyUserService().getListByCompanyId(companyId);

                for (BCompanyUser bCompanyUser : BCompanyUserList) {
                    userIdList.add(bCompanyUser.getUserId());
                }
            } else {
                userIdList.add(userId);
            }
            return userIdList;
        } catch (Exception e) {
            LOGGER.error("select company user error : {}.", e);
            throw new BusinessException("查询公司下用户异常");
        }
    }

    private Map<String, Object> getList(PageVo page, List<Integer> statusList) {
        LOGGER.info("select cwaybill list getList params page : {}, statusList : {}.", page, statusList);
        try {
            Map<String, Object> paramsMap = new HashMap<>();
            if (null != page) {
                paramsMap.put("limitStart", page.getStartIndex());
                paramsMap.put("limitEnd", page.getPageSize());
                if (StringUtils.isNotEmpty(page.getOrder())) {
                    paramsMap.put("orderByClause", page.getOrder());
                } else {
                    paramsMap.put("orderByClause", " w.update_time DESC");
                }
            }

            List<Long> userIdList = this.getUserIdList();
            if (!statusList.contains(WaybillStatusEnum.WAITBID.getValue())) {
                if (CollectionUtils.isNotEmpty(userIdList)) {
                    paramsMap.put("userIdList", userIdList);
                }
            }

            paramsMap.put("statusList", statusList);
            paramsMap.put("isVeneer", true);

            if (null != page) {
                page.setTotalRecord(this.getCWaybillViewMapper().countVeneersByConditons(paramsMap));
            }
            List<CWaybillVeneerVo> list = this.getCWaybillViewMapper().selectVeneersByConditons(paramsMap);
            for (CWaybillVeneerVo cWaybillVeneerVo : list) {
                String branbVehicleshow = "";
                List<String> branbVehicles = cWaybillVeneerVo.getBranbVehicles();
                for (String string : branbVehicles) {
                    branbVehicleshow = branbVehicleshow.concat(" " + string);
                }
                cWaybillVeneerVo.setDetail(branbVehicleshow);
            }

            Map<String, Object> map = new HashMap<>();
            if (null != page) {
                map.put("page", page);
            }
            map.put("waybills", list);

            return map;
        } catch (Exception e) {
            LOGGER.error("select cwaybill list getList params page : {}, statusList : {}, error : {}.", page, statusList, e);
            throw new BusinessException("查询运单列表异常");
        }
    }

    @Override
    public Map<String, Object> getNoGrabListByPage(PageVo page) {
        LOGGER.info("select getNoGrabListByPage params page : {}.", page);
        List<Integer> statusList = new ArrayList<>();
        statusList.add(WaybillStatusEnum.WAITBID.getValue());
        Map<String, Object> map = this.getList(null, statusList);
        List<CWaybillVeneerVo> waybills = (List<CWaybillVeneerVo>) map.get("waybills");

        if (CollectionUtils.isNotEmpty(waybills)) {
            page.setTotalRecord(waybills.size());

            //查询redis中已指派的运单主键
            List<String> strings = cWaybillService.getAllCWaybillWithUserFromRedis();
            if (CollectionUtils.isNotEmpty(strings)) {

                //获取所有已指派的运单主键
                final List<Long> cWaybillIds = strings.stream().mapToLong(s -> NumberUtils.toLong(s.substring(0, s.indexOf(":")))).collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

                if (CollectionUtils.isNotEmpty(cWaybillIds)) {
//                List<CWaybillVeneerVo> cwWithUsers = waybills.stream().filter(vo -> cWaybillIds.contains(id -> id == vo.getId())).collect(Collectors.toList());

                    //查询指派给当前用户的运单主键
                    List<Long> userIdList = this.getUserIdList();
//
                    List<Long> removeIds = strings.stream().filter(
                            s -> !userIdList.contains(NumberUtils.toLong(s.split(":")[1])))
                            .mapToLong(s -> NumberUtils.toLong(s.split(":")[0])).collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

                    if (CollectionUtils.isNotEmpty(removeIds)) {
                        waybills = waybills.stream().filter(vo -> !removeIds.contains(vo.getId())).collect(Collectors.toList());
                        if (null != page) {
                            int startIdx = page.getStartIndex();
                            int endIdx = page.getPageSize() * page.getPageNo();
                            waybills = waybills.subList(startIdx, waybills.size() > endIdx == true ? endIdx : waybills.size());
                        }
                        map.put("waybills", waybills);
                    }
                }
            }
        }

        map.put("page", page);
        return map;
    }

    @Override
    public Map<String, Object> getAlreadyGrabListByPage(PageVo page) {
        LOGGER.info("select getAlreadyGrabListByPage params page : {}.", page);
        List<Integer> statusList = new ArrayList<>();
        statusList.add(WaybillStatusEnum.ALREADYBID.getValue());
        statusList.add(WaybillStatusEnum.WAITEXTRACTED.getValue());
        statusList.add(WaybillStatusEnum.WAITCOMPLETE.getValue());
        statusList.add(WaybillStatusEnum.COMPLETED.getValue());
        return this.getList(page, statusList);
    }

    @Override
    public Map<String, Object> getDoneListByPage(PageVo page) {
        LOGGER.info("select getDoneListByPage params page : {}.", page);
        List<Integer> statusList = new ArrayList<>();
        statusList.add(WaybillStatusEnum.DONE.getValue());
        return this.getList(page, statusList);
    }

    @Override
    public Long grabOne(Long id, Boolean isVineer) throws Exception {
        LOGGER.info("user grabOne params id : {}.", id);
        if (id == null || id == 0) {
            LOGGER.error("id is null");
            throw new BusinessException("运单ID不能为空！");
        }

        // 获取用户信息判断用户是否上线
        UserShowVo user = this.getUserService().getCurrentUser();
        if (UserTypeEnum.COMPANY.getValue() != user.getUserType()) {
            List<CWaybillVeneerVo> cWaybillVeneerVos = this.getExecutionList(true);
            if (CollectionUtils.isNotEmpty(cWaybillVeneerVos)) {
                LOGGER.info("Existing in road waybill, cannot repeat orders");
                throw new BusinessException("200", "已有在途运单，不能重复接单！");
            }
            if (UserStatusEnum.F.getValue() == user.getUserStatus()) {
                LOGGER.info("user status is false");
                throw new BusinessException("100", "用户未上线！");
            }
            // 查询用户车辆信息是否验证
            this.getDriverCertInfoService().verifyTheCurrentUservehicleInformationAudit(user.getId(), isVineer);
        }

        //判断该运单是否是指定给该用户的
        Long userByCWaybillFromRedis = cWaybillService.getUserByCWaybillFromRedis(id);
        if (null != userByCWaybillFromRedis) {
            if (user.getId().longValue() != userByCWaybillFromRedis.longValue()) {
                LOGGER.error("grabOne userByCWaybillFromRedis != the current user`s id");
                throw new BusinessException("运单未指定给当前用户！");
            }
        }

        String redisKey = null;
        String redisValue = null;
        try {
            redisKey = REDIS_LOCK_WAYBILL_GRAB_PRE + id;
            // 分布锁 多人同时接单
            String lockValue = redisCacheManager.tryLock(redisKey, 5);
            if (StringUtils.isNotEmpty(lockValue)) {
                LOGGER.info("运单:" + id + "获取分布锁成功,继续执行接单流程.");
                redisValue = lockValue;
            } else {
                LOGGER.info("运单:" + id + "获取分布锁失败,已有人接单, 返回.");
                throw new BusinessException("255", "手气太差了，运单已被抢！继续加油哟！");
            }

            // 查询发布状态的运单
            CWaybillExample waybillExample = new CWaybillExample();
            waybillExample.createCriteria().andIdEqualTo(id); // .andWaybillTypeEqualTo(WaybillTypeEnum.BIDSELF.getValue());
            List<CWaybill> waybills = this.getCWaybillMapper().selectByExample(waybillExample);
            if (CollectionUtils.isEmpty(waybills)) {
                LOGGER.error("waybills is empty");
                throw new BusinessException("获取运单信息失败！");
            }
            CWaybill waybill = waybills.get(0);
            if (waybill.getStatus() != WaybillStatusEnum.WAITBID.getValue()) {
                LOGGER.error("cwaybill status is not published");
                throw new BusinessException("255", "手气太差了，运单已被抢！继续加油哟！");
            }

            Long userId = user.getId();
            // 更新运单状态
            waybill.setStatus(WaybillStatusEnum.WAITEXTRACTED.getValue());
            waybill.setBidderId(userId);
            waybill.setBidderType(user.getUserType());
            waybill.setUpdateTime(new Date());
            if (user.getUserType() == UserTypeEnum.DRIVER.getValue()) {
                // waybill.setStatus(WaybillStatusEnum.WAITEXTRACTED.getValue());
                waybill.setActDriver(userId);
            }
            this.getCWaybillMapper().updateByPrimaryKeySelective(waybill);

            // 添加联系人 信息
            this.addContants(userId, waybill.getId());

            // 修改客户订单状态
            CWaybillDetailExample detailExample = new CWaybillDetailExample();
            detailExample.createCriteria().andWaybillIdEqualTo(waybill.getId());
            List<CWaybillDetail> details = this.getCWaybillDetailMapper().selectByExample(detailExample);
            List<Long> serviceOrderIdList = new ArrayList<>();
            for (CWaybillDetail cWaybillDetail : details) {
                Long serviceOrderId = cWaybillDetail.getServiceOrderId();
                if (cWaybillDetail.getServiceDispatchTimes() == 1) {
                    SServiceOrder sServiceOrder = new SServiceOrder();
                    sServiceOrder.setId(serviceOrderId);
                    sServiceOrder.setStatus(SServiceOrderStatusEnum.WAIT_EXTRACT.getValue());
                    this.getSServiceOrderMapper().updateByPrimaryKeySelective(sServiceOrder);

                    // 提车安排通知
                    serviceOrderIdList.add(serviceOrderId);
                }

                // 保存接单记录 每个运单明细增加一条
                // 保存接单记录
                Long bidId = this.getWaybillBidService().addWayBillBid(serviceOrderId, waybill.getId(), userId, true);
                LOGGER.info("接单记录bidId : {}.", bidId);

                // 修改客户订单状态 添加日志
                this.getSOrderService().updateOrderStatusBySid(serviceOrderId);
            }

            // 提车安排通知
            this.sendExtractMessage(serviceOrderIdList, userId);

            //判断此订单是否是在redis中指派的，如果是则删除
            // 同城运单 接单后移除redis数据
            this.getCWaybillService().isExistInRedis(waybill.getId(), userId, true);

            return waybill.getId();
        } catch (Exception e) {
            LOGGER.error("user grabOne cwaybill error : {}.", e);
            throw new BusinessException("该运单已被接单");
        } finally {
            redisCacheManager.releaseLock(redisKey, redisValue);
        }
    }

    // 提车安排通知
    public void sendExtractMessage(List<Long> serviceOrderIdList, Long userId) {
        LOGGER.info("dirver grab one order sendExtractMessage params serviceOrderIdList : {}, userId : {}.", serviceOrderIdList, userId);
        try {
            Map<Long, List<Long>> map = new HashMap<>();
            Boolean isVeneer = false;
            for (Long sId : serviceOrderIdList) {
                SServiceOrder sServiceOrder = this.getSServiceOrderService().selectById(sId);
                LOGGER.info("sServiceOrder : {}", sServiceOrder);
                Long customerOrderId = sServiceOrder.getCustomerOrderId();
                LOGGER.info("customerOrderId : {}", customerOrderId);
                isVeneer = sServiceOrder.getIsVeneer();
                LOGGER.info("isVeneer : {}", isVeneer);
                if (map.keySet().contains(customerOrderId)) {
                    List<Long> list = map.get(customerOrderId);
                    list.add(sId);
                    map.put(customerOrderId, list);
                } else {
                    List<Long> list = new ArrayList<>();
                    list.add(sId);
                    map.put(customerOrderId, list);
                }
                LOGGER.info("sendExtractMessage map : {}", map);
            }

            SUser user = this.getUserService().getById(userId);
            LOGGER.info("sendExtractMessage current user : {}", user);
            LOGGER.info("sendExtractMessage current user user.getUserType(): {}", user.getUserType());
            if (user.getUserType() == UserTypeEnum.DRIVER.getValue()) {
                CDriverCertinfo driverInfo = this.getTruckInfoService().queryDriverInfoByUserId(userId);
                LOGGER.info("sendExtractMessage driverInfo: {}", driverInfo);
                String phoneDriver = user.getPhone();
                LOGGER.info("sendExtractMessage phoneDriver: {}", phoneDriver);
                Set<Long> keySet = map.keySet();
                String tplValue = "";
                long tplId = 0L;
                for (Long long1 : keySet) {
                    SOrder sorder = this.getSOrderService().selectByPrimaryKey(long1);
                    LOGGER.info("sendExtractMessage sorder: {}", sorder);
                    String departAddr = sorder.getDepartCityName();
                    LOGGER.info("sendExtractMessage departAddr: {}", departAddr);
                    String receiptAddr = sorder.getReceiptCityName();
                    LOGGER.info("sendExtractMessage receiptAddr: {}", receiptAddr);
                    String orderCode = sorder.getOrderCode();
                    LOGGER.info("sendExtractMessage orderCode: {}", orderCode);
                    String departPerson = user.getRealName();
                    LOGGER.info("sendExtractMessage departPerson: {}", departPerson);
                    String idno = driverInfo.getIdno();
                    LOGGER.info("sendExtractMessage idno: {}", idno);
                    Integer carAmount = map.get(long1).size();
                    LOGGER.info("sendExtractMessage carAmount: {}", carAmount);
                    String departCounty = sorder.getDepartCountyName();
                    LOGGER.info("sendExtractMessage departCounty: {}", departCounty);
                    String receiptCounty = sorder.getReceiptCountyName();
                    LOGGER.info("sendExtractMessage receiptCounty: {}", receiptCounty);
                    if (isVeneer) {
                        String time = "1";

                        tplValue = URLEncoder.encode("#phone#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(phoneDriver, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#time#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(time, JavaSmsApi.getENCODING());

                        tplId = JavaSmsApi.VENEER_EXTRACTED_TPL_ID;
                        this.getSendMessageService().sendMessage(tplId, tplValue, sorder.getDepartPhone());
                        LOGGER.info("sendExtractMessage tplId: {}, tplValue: {}, DepartPhone: {}", tplId, tplValue, sorder.getDepartPhone());
                        long timePerson = DateUtils.getDiffHours(sorder.getArriveDate());
                        LOGGER.info("sendExtractMessage timePerson: {}", timePerson);
                        if (timePerson <= 0) {
                            timePerson = 1L;
                        }
                        /** Long tplIdPerson = JavaSmsApi.veneer_jiaocheren_tpl_id;
                         String tplValuePerson = URLEncoder.encode("#phone#",JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(phoneDriver, JavaSmsApi.getENCODING());
                         tplValuePerson += "&" + URLEncoder.encode("#time#",JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(timePerson+"", JavaSmsApi.getENCODING());
                         this.getSendMessageService().sendMessage(tplIdPerson, tplValuePerson, sorder.getReceiptPhone()); */

                        // 同城业务向下单人消息推送
                        // 查询最后一次登录设备的UUID
                        LOGGER.info("sendExtractMessage serviceOrderId: {}", serviceOrderIdList.get(0));
                        SServiceOrderVehicle serviceOrderVehicle = this.getSServiceOrderVehicleService().selectByServiceOrderId(serviceOrderIdList.get(0) + "");
                        LOGGER.info("sendExtractMessage serviceOrderVehicle: {}", serviceOrderVehicle);
                        BVehicleBrand brand = this.getBVehicleBrandService().selectById(serviceOrderVehicle.getBrandId());
                        LOGGER.info("sendExtractMessage brand: {}", brand);
                        BVehicle vehicle = this.getBVehicleService().selctById(serviceOrderVehicle.getVehicleId());
                        LOGGER.info("sendExtractMessage vehicle: {}", vehicle);

                        SUserDevicesExample example = new SUserDevicesExample();
                        example.setOrderByClause("id desc");
                        example.createCriteria().andUserIdEqualTo(sorder.getUserId());
                        LOGGER.info("sendExtractMessage sorder.getUserId(): {}", sorder.getUserId());
                        List<SUserDevices> sUserDevices = this.getSUserDevicesMapper().selectByExample(example);
                        LOGGER.info("sendExtractMessage sUserDevices: {}", JSONArray.toJSONString(sUserDevices));
                        if (CollectionUtils.isNotEmpty(sUserDevices)) {
                            SUserDevices devices = sUserDevices.get(0);
                            List<String> aliases = new ArrayList<String>();
                            aliases.add(devices.getUuid().replaceAll("-", "").replaceAll("_", ""));
                            LOGGER.info("sendExtractMessage aliases: {}", JSONArray.toJSONString(aliases));
                            // 推送消息
                            String msg = "尊敬的客户，" + "从" + departCounty + "至" + receiptCounty + "，" + brand.getBrandName() + vehicle.getVehicleName()
                                    + "已接单，司机正前往提车，预计" + time + "小时内到达，司机联系电话" + phoneDriver + "，请通知提车人做好发车准备！";
                            LOGGER.info("msg: {}, devices: {}", msg, devices.getUuid());
                            this.getJPushService().sendMsgKyleByAliases(aliases, msg);
                        }
                    } else {
                        tplValue = URLEncoder.encode("#departAddr#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(departAddr, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#receiptAddr#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(receiptAddr, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#orderCode#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(orderCode, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#departPerson#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(departPerson, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#idno#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(idno, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#phone#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(phoneDriver, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#carAmount#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(carAmount + "", JavaSmsApi.getENCODING());

                        tplId = JavaSmsApi.EXTRACTED_TPL_ID;
                        String phone = null;
                        Long userId2 = sorder.getUserId();
                        SUser userOrder = this.getUserService().selectByPrimaryKey(userId2);
                        if (null != userOrder) {
                            phone = userOrder.getPhone();
                        }
                        if (null != phone) {
                            this.getSendMessageService().sendMessage(tplId, tplValue, phone);
                        }
                    }
                }
            }
        } catch (Exception e) {
            LOGGER.error("dirver grab one order sendExtractMessage error : {}.", e);
            throw new BusinessException("司机接单,发送提车安排通知异常");
        }
    }

    /**
     * 生成运单 如果是派单 判断指派人 司机／承运商
     *
     * @param userId
     * @param waybillId
     */
    private void addContants(Long userId, Long waybillId) {
        Date currentTime = new Date();
        try {
            LOGGER.info("create cwaybill add contants params userId : {}, waybillId : {}.", userId, waybillId);
            SUser user = this.getUserService().getById(userId);
            if (user != null && user.getUserType() == UserTypeEnum.DRIVER.getValue()) {
                CDriverCertinfo driverInfo = this.getTruckInfoService().queryDriverInfoById(userId);
                if (driverInfo == null) {
                    LOGGER.info("create cwaybill add contants params driverInfo is not null");
                    throw new BusinessException("添加司机信息认证信息为空");
                }
                CTruckInfo truckInfo = this.getTruckInfoService().queryTruckInfoById(userId);
                if (truckInfo == null) {
                    LOGGER.info("create cwaybill add contants params truckInfo is not null");
                    throw new BusinessException("添加司机信息车辆信息为空");
                }
                LOGGER.info("create cwaybill add contacts userId : {}, waybillId : {}.", userId, waybillId);

                // 如果指派人为司机 则插入到contacts表中
                CWaybillContacts cWaybillContacts = new CWaybillContacts();
                cWaybillContacts.setCreateTime(currentTime);
                cWaybillContacts.setUpdateTime(currentTime);
                cWaybillContacts.setContact(user.getRealName());
                cWaybillContacts.setIdno(driverInfo.getIdno());
                cWaybillContacts.setLicenseNumner(truckInfo.getTractorNumber());
                cWaybillContacts.setPhone(user.getPhone());
                cWaybillContacts.setWaybillId(waybillId);
                List<CWaybillContacts> list = new ArrayList<CWaybillContacts>();
                cWaybillContacts.setType(WaybillContactsTypeEnum.DRIVER.getValue());
                list.add(cWaybillContacts);
                LOGGER.info("create cwaybill add contacts userId : {}, waybillId : {}, contactsType : {}.", userId,
                        waybillId, WaybillContactsTypeEnum.DRIVER.getValue());
                CWaybillContacts cWaybillContacts20 = new CWaybillContacts();
                BeanUtils.copyProperties(cWaybillContacts, cWaybillContacts20);
                cWaybillContacts20.setType(WaybillContactsTypeEnum.DEPARTPERSON.getValue());
                list.add(cWaybillContacts20);
                LOGGER.info("create cwaybill add contacts userId : {}, waybillId : {}, contactsType : {}.", userId,
                        waybillId, WaybillContactsTypeEnum.DEPARTPERSON.getValue());
                CWaybillContacts cWaybillContacts30 = new CWaybillContacts();
                BeanUtils.copyProperties(cWaybillContacts, cWaybillContacts30);
                cWaybillContacts30.setType(WaybillContactsTypeEnum.RECEIPTPERSON.getValue());
                list.add(cWaybillContacts30);
                LOGGER.info("create cwaybill add contacts userId : {}, waybillId : {}, contactsType : {}.", userId,
                        waybillId, WaybillContactsTypeEnum.RECEIPTPERSON.getValue());

                this.getCWaybillContactsService().batchInsert(list);
            } else {
                LOGGER.info("add contancts grab user is company, not add contancts userId : {}.", userId);
            }
        } catch (Exception e) {
            LOGGER.error("create cwaybill add contants error : {}.", e);
            throw new BusinessException("创建运单添加交接人信息异常.");
        }
    }

    @Override
    public Long confirmSend(Long id, String attachs, SysAdminUser adminUser) throws Exception {
        LOGGER.info("confirmSend params : {}, {}", id, attachs);
        // 查询可发车状态的运单
        CWaybill cWaybill = this.getCWaybillMapper().selectByPrimaryKey(id);
        if (null == cWaybill) {
            LOGGER.error("cWaybill is empty id : {}.", id);
            throw new BusinessException("获取运单信息失败！");
        }

        // 当前用户
        UserVo user = null;
        if (adminUser == null) {
            user = this.getUserService().getCurrentUserVo();
        }
        // 保存附件
        List<AttachForm> objs = JSONArray.parseArray(attachs, AttachForm.class);
        if (CollectionUtils.isNotEmpty(objs)) {
            AttachForm af;
            CWaybillAttach attach = new CWaybillAttach();
            attach.setWaybillId(id);
            if (null != user) {
                attach.setUserId(user.getId());
                attach.setUserName(user.getUsername());
            } else {
                user = new UserVo(adminUser.getId(), adminUser.getUsername(), adminUser.getPassword(), "", true, 0);
                attach.setUserId(adminUser.getId());
                attach.setUserName(adminUser.getUsername());
            }
            attach.setCategory(AttachCategoryEnumWaybill.RECEIPT.getValue());// 提车照片
            for (int i = 0; i < objs.size(); i++) {
                af = objs.get(i);
                attach.setPicKey(af.getImage());
                AttachTypeEnum typeEnum = AttachTypeEnum.getByValue(af.getType());
                if (typeEnum == null) {
                    LOGGER.error("typeEnum is null");
                    throw new BusinessException("图片类型错误!");
                }
                attach.setType(typeEnum.getValue());

                // 照片去重
                CWaybillAttachExample attachExample = new CWaybillAttachExample();
                attachExample.createCriteria().andWaybillIdEqualTo(id).andCategoryEqualTo(AttachCategoryEnumWaybill.RECEIPT.getValue()).andTypeEqualTo(typeEnum.getValue());
                List<CWaybillAttach> attachlist = this.getCWaybillAttachMapper().selectByExample(attachExample);
                if (Collections.isEmpty(attachlist)) {
                    this.getCWaybillAttachMapper().insertSelective(attach);
                } else {
                    Long oldId = attachlist.get(0).getId();
                    attach.setId(oldId);
                    this.getCWaybillAttachMapper().updateByPrimaryKeySelective(attach);
                }
            }
        }

        if (cWaybill.getIsVeneer()) {
            return this.updateStatus(cWaybill.getId(), WaybillStatusEnum.WAITCOMPLETE.getValue(), SServiceOrderStatusEnum.HAVE_ISSUSD.getValue(), user);
        }
        return this.updateStatus(cWaybill.getId(), WaybillStatusEnum.EXTRACTED.getValue(), 0, user);
    }

    public Long updateStatus(Long id, int status, int sStatus, UserVo user) {
        LOGGER.info("updateStatus params : {}, {}, {}, {}", id, status, sStatus, user);
        if (id == null) {
            LOGGER.error("id is null");
            throw new BusinessException("运单id不能为空！");
        }
        if (0 == status) {
            LOGGER.error("status is 0");
            throw new BusinessException("状态不能为0！");
        }
        try {
            CWaybill waybill = new CWaybill();
            waybill.setId(id);
            waybill.setStatus(status);
            this.getCWaybillMapper().updateByPrimaryKeySelective(waybill);

            // 添加运单状态变更日志
            CWaybillStatusLog log = new CWaybillStatusLog();
            log.setUpdateTime(new Date());
            log.setCreatTime(new Date());
            log.setCategory(StatusCategoryEnum.PROCESS.getValue());
            log.setComment("司机上传照片修改运单状态");
            log.setUserId(user.getId());
            log.setUserName(user.getUsername());
            log.setWaybillId(id);
            log.setStatus(status);
            this.getCWaybillStatusLogService().addCWaybillStatusLog(log);

            // 更新订单状态
            // this.getSOrderService().updateStatusForWaybill(waybill.getOrderId(), status);
            // 更新服务订单状态
            if (sStatus != 0) {
                CWaybillDetailExample detailExample = new CWaybillDetailExample();
                detailExample.createCriteria().andWaybillIdEqualTo(id);
                List<CWaybillDetail> details = this.getCWaybillDetailMapper().selectByExample(detailExample);
                for (CWaybillDetail cWaybillDetail : details) {
                    SServiceOrder sServiceOrder = new SServiceOrder();
                    sServiceOrder.setId(cWaybillDetail.getServiceOrderId());
                    sServiceOrder.setStatus(sStatus);
                    this.getSServiceOrderMapper().updateByPrimaryKeySelective(sServiceOrder);

                    SServiceOrderStatusLog serviceOrderStatusLog = new SServiceOrderStatusLog();
                    serviceOrderStatusLog.setCreateTime(new Date());
                    serviceOrderStatusLog.setServiceOrderId(cWaybillDetail.getServiceOrderId());
                    serviceOrderStatusLog.setStatus(sStatus);
                    serviceOrderStatusLog.setUserId(user.getId());
                    serviceOrderStatusLog.setUserName(user.getUsername());
                    this.getSServiceOrderStatusLogService().addLog(serviceOrderStatusLog);

                    if (cWaybillDetail.getServiceDispatchTimes() == 1) {
                        SServiceOrderTrail serviceOrderTrail = new SServiceOrderTrail();
                        serviceOrderTrail.setCreateTime(new Date());
                        serviceOrderTrail.setServiceOrderId(cWaybillDetail.getServiceOrderId());
                        serviceOrderTrail.setType(SServiceOrderTrailTypeEnum.SERVICE_ORDER_STATUS.getValue());
                        serviceOrderTrail.setStatus(sStatus);
                        serviceOrderTrail.setInfo(SServiceOrderStatusEnum.getByValue(sStatus).getText());
                        this.getSServiceOrderTrailMapper().insertSelective(serviceOrderTrail);
                    }
                }
            }
            return waybill.getId();
        } catch (Exception e) {
            LOGGER.error("udpate cwaybill status sservice order status error : {}.", e);
            throw new BusinessException("更新运单状态异常");
        }
    }

    @Override
    public Long confirmDliver(Long id, String attachs, SysAdminUser adminUser) {
        LOGGER.info("upload jiaoche piccture params id : {}, attachs : {}.", id, attachs);
        try {
            // 查询可交车状态的运单
            CWaybill cWaybill = this.getCWaybillMapper().selectByPrimaryKey(id);
            if (null == cWaybill) {
                LOGGER.error("waybills is empty");
                throw new BusinessException("获取运单信息失败！");
            }

            // 当前用户
            UserVo user = null;
            if (adminUser == null) {
                user = this.getUserService().getCurrentUserVo();
            }

            // 保存附件
            List<AttachForm> objs = JSONArray.parseArray(attachs, AttachForm.class);
            if (CollectionUtils.isNotEmpty(objs)) {
                AttachForm af;
                CWaybillAttach attach = new CWaybillAttach();
                attach.setWaybillId(id);
                if (null != user) {
                    attach.setUserId(user.getId());
                    attach.setUserName(user.getUsername());
                } else {
                    user = new UserVo(adminUser.getId(), adminUser.getUsername(), adminUser.getPassword(), "", true, 0);
                    attach.setUserId(adminUser.getId());
                    attach.setUserName(adminUser.getUsername());
                }
                attach.setCategory(AttachCategoryEnumWaybill.DELIVER.getValue());// 交车照片
                for (int i = 0; i < objs.size(); i++) {
                    af = objs.get(i);
                    attach.setPicKey(af.getImage());
                    AttachTypeEnum typeEnum = AttachTypeEnum.getByValue(af.getType());
                    if (typeEnum == null) {
                        LOGGER.error("typeEnum is null");
                        throw new BusinessException("图片类型错误!");
                    }
                    attach.setType(typeEnum.getValue());
                    // 照片去重
                    CWaybillAttachExample attachExample = new CWaybillAttachExample();
                    attachExample.createCriteria().andWaybillIdEqualTo(id).andCategoryEqualTo(AttachCategoryEnumWaybill.DELIVER.getValue()).andTypeEqualTo(typeEnum.getValue());
                    List<CWaybillAttach> attachlist = this.getCWaybillAttachMapper().selectByExample(attachExample);
                    if (Collections.isEmpty(attachlist)) {
                        this.getCWaybillAttachMapper().insertSelective(attach);
                    } else {
                        Long oldId = attachlist.get(0).getId();
                        attach.setId(oldId);
                        this.getCWaybillAttachMapper().updateByPrimaryKeySelective(attach);
                    }
                }
            }
            return this.updateStatus(cWaybill.getId(), WaybillStatusEnum.COMPLETED.getValue(), 0, user);
        } catch (Exception e) {
            LOGGER.info("upload jiaoche piccture params id : {}, attachs : {}, error ; {}.", id, attachs, e);
            throw new BusinessException("上传交车照片异常");
        }
    }

    @Override
    public WaybillNewVo getById(Long id) {
        if (id == null || id == 0) {
            LOGGER.error("id is null");
            throw new BusinessException("运单id不能为空！");
        }
        try {
            WaybillNewVo vo = this.getSWaybillViewMapper().selectById(id);

            // 查询运单信息
            if (vo == null) {
                LOGGER.error("vo is null");
                throw new BusinessException("获取运单信息失败!");
            }

            if (vo.getIsVeneer()) {
                vo.setShipmentDate(vo.getLoadTime());
                vo.setArriveDate(vo.getUnloadTime());
            }
            // 获取车型logo
            List<CWaybillDetailVo> vehicles = vo.getVehicles();
            if (CollectionUtils.isNotEmpty(vehicles)) {
                VehicleBrandVo brand = new VehicleBrandVo();
                for (int i = 0; i < vehicles.size(); i++) {
                    brand = vehicles.get(i).getBrand();
                    if (brand != null) {
                        if (StringUtils.isNotBlank(brand.getLogo())) {
                            vehicles.get(i).setBrandLogo(QiniuUtils.generateDownloadTicket(
                                    HYCUtils.getConstantPropertiesLoader().getProperty(QiniuConstant.QINIU_LOGO_BUCKET),
                                    brand.getLogo(), "1", "200", "200"));
                        }
                    }
                }
                vo.setDetail(vehicles.size() + "辆");
            }

            // 处理图片
            this.buildAttach(vo);
            return vo;
        } catch (Exception e) {
            LOGGER.error("select cwaybill detail error : {}.", e);
            throw new BusinessException("查询运单明细异常");
        }
    }

    private void buildAttach(WaybillNewVo vo) {
        LOGGER.info("buildAttach params : {}", vo);
        // 发车照片
        List<AttachVo> loadPics = vo.getSendPics();
        if (CollectionUtils.isNotEmpty(loadPics)) {
            AttachVo attach = new AttachVo();
            for (int i = 0; i < loadPics.size(); i++) {
                attach = loadPics.get(i);
                attach.setPicKey(QiniuUtils.generateDownloadTicket(attach.getPicKey(), ""));
                attach.setTypeText(AttachTypeEnum.getByValue(attach.getType()).getText());
            }
        }

        // 交车照片
        List<AttachVo> unloadPics = vo.getDeliverPics();
        if (CollectionUtils.isNotEmpty(unloadPics)) {
            AttachVo attach = new AttachVo();
            for (int i = 0; i < unloadPics.size(); i++) {
                attach = unloadPics.get(i);
                attach.setPicKey(QiniuUtils.generateDownloadTicket(attach.getPicKey(), ""));
                attach.setTypeText(AttachTypeEnum.getByValue(attach.getType()).getText());
            }
        }
    }

    @Override
    public Map<String, Object> getOrderCount() {
        LOGGER.error("select driver order count.");
        try {
            List<Long> userIdList = this.getUserIdList();
            CWaybillExample example = new CWaybillExample();
            example.createCriteria().andBidderIdIn(userIdList).andStatusEqualTo(WaybillStatusEnum.DONE.getValue());
            int count = this.getCWaybillMapper().countByExample(example);
            Map<String, Object> map = new HashMap<>();
            map.put("count", count);
            return map;
        } catch (Exception e) {
            LOGGER.error("select driver order count error : {}.", e);
            throw new BusinessException("查询运单数异常");
        }
    }

    @Override
    public List<CWaybillVeneerVo> getExecutionList(Boolean isIntracity) {
        LOGGER.info("getExecutionList param : {}", isIntracity);

        Map map = new HashMap();

        if (null == isIntracity) {
            isIntracity = false;
        }
        map.put("isVeneer", isIntracity);

        //执行中状态
        List<Integer> statusList = new ArrayList<>();
//				ALREADYBID(20, "已接单"),
//				WAITEXTRACTED(30, "待提车"),
//				EXTRACTED(40, "已提车"),
//				WAITSTART(50, "待发车"),
//				WAITCOMPLETE(60, "待交车"),
//				COMPLETED(80, "已交车"),
        statusList.add(WaybillStatusEnum.ALREADYBID.getValue());
        statusList.add(WaybillStatusEnum.WAITEXTRACTED.getValue());
        statusList.add(WaybillStatusEnum.EXTRACTED.getValue());
        statusList.add(WaybillStatusEnum.WAITSTART.getValue());
        statusList.add(WaybillStatusEnum.WAITCOMPLETE.getValue());
        statusList.add(WaybillStatusEnum.COMPLETED.getValue());

        return this.getListByStatus(statusList, map);
    }

    @Override
    public List<CWaybillVeneerVo> getListByStatus(List<Integer> statusList, Map<String, Object> params) {
        LOGGER.info("getListByStatus params : statusList : {}, {}", statusList, params);
        try {
            Map<String, Object> paramsMap = new HashMap<>();

            List<Long> userIdList = this.getUserIdList();
            if (!statusList.contains(WaybillStatusEnum.WAITBID.getValue())) {
                if (CollectionUtils.isNotEmpty(userIdList)) {
                    paramsMap.put("userIdList", userIdList);
                }
            }

            paramsMap.put("statusList", statusList);
            paramsMap.put("isVeneer", params.get("isVeneer") == null ? false : params.get("isVeneer"));

            List<CWaybillVeneerVo> list = this.getCWaybillViewMapper().selectVeneersByConditons(paramsMap);
            if (CollectionUtils.isNotEmpty(list)) {
                return list;
            }

            return null;
        } catch (Exception e) {
            LOGGER.error("getListByStatus : {}, error : {}.", statusList, e);
            throw new BusinessException("查询运单列表异常");
        }
    }

}